<?php
declare(strict_types=1);

namespace App\Helper;

use Hyperf\Utils\ApplicationContext;
use Hyperf\Utils\Filesystem\FileNotFoundException;
use Hyperf\Utils\Filesystem\Filesystem;
use Hyperf\Utils\MimeTypeExtensionGuesser;
use Hyperf\Utils\Str;
use SplFileInfo;

class FileHelper
{
    private static $fileSystem = null;

    public static function getExtension(string $strFile): string
    {
        return static::getFileSystem()->extension($strFile);
    }

    public static function getFileSystem(): Filesystem
    {
        is_null(self::$fileSystem) && self::$fileSystem = new Filesystem();
        return self::$fileSystem;
    }

    public static function delDir(string $strDir, string $rooPath = ''): bool
    {
        $strDir = static::checkPath($strDir, $rooPath);
        if (!$strDir) {
            return false;
        }
        if (!file_exists($strDir)) {
            return true;
        }
        if (is_file($strDir)) {
            return false;
        }
        return static::getFileSystem()->deleteDirectory($strDir);
    }

    public static function checkPath(string $strPath, string $strRooPath = ''): ?string
    {
        $strRe = null;
        $strPathReal = realpath($strPath);
        if ($strPathReal) {
            $strRe = $strPathReal;
        } else {
            $arr = explode('/', trim($strPath, '/'));
            if (array_intersect(['.', '..', '\\'], $arr)) {
                return null;
            }
            $strRe = '';
            foreach ($arr as $s) {
                empty($s) || $strRe .= '/' . $s;
            }
        }
        if ($strRe && $strRooPath && !Str::startsWith($strRe, $strRooPath)) {
            return null;
        }
        return $strRe;
    }

    public static function getMineTypeByFileInfo(SplFileInfo $fileInfo): ?string
    {
        return ApplicationContext::getContainer()
            ->get(MimeTypeExtensionGuesser::class)
            ->guessMimeType($fileInfo->getExtension());
    }

    public static function getMineType(string $filePath): ?string
    {
        return static::getFileSystem()->mimeType($filePath) ?: null;
    }

    public static function del(string $path, string $rootPath = ''): bool
    {
        $path = self::checkPath($path, $rootPath);
        if (!$path) {
            return false;
        }
        return file_exists($path) && is_file($path) && unlink($path);
    }

    public static function read(string $filePath, string $rootPath = ''): ?string
    {
        $filePath = self::checkPath($filePath, $rootPath);
        if (!$filePath) {
            return null;
        }
        try {
            return static::getFileSystem()->get($filePath);
        } catch (FileNotFoundException $e) {
            return null;
        }
    }

    public static function writePhpVar(string $filePath, $phpVar, string $rootPath = ''): bool
    {
        $fileContent = '<?php' . PHP_EOL . 'return ' . var_export($phpVar, true) . ';' . PHP_EOL;
        return self::write($filePath, $fileContent, 'w', $rootPath);
    }

    public static function write(string $filePath, string $fileContent = '', string $mod = 'w', string $rootPath = ''): bool
    {
        $filePath = self::checkPath($filePath, $rootPath);
        if (!$filePath) {
            return false;
        }
        self::makeDir(dirname($filePath));
        switch ($mod) {
            case 'a':
                return !static::getFileSystem()->append($filePath, $fileContent) === false;
            default:
                return !static::getFileSystem()->put($filePath, $fileContent) === false;
        }
    }

    public static function makeDir(string $dir, int $mod = 0755, string $rooPath = ''): bool
    {
        $dir = static::checkPath($dir, $rooPath);
        if (!$dir) {
            return false;
        }
        return (file_exists($dir) && is_dir($dir)) || mkdir($dir, $mod, true);
    }

    public static function niceSize(int $intLen, string $strGlue = ''): string
    {
        $arr = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
        for ($i = 0; $intLen >= 1024 && $i < 5; $i++) {
            $intLen /= 1024;
        }
        return (floor($intLen * 100) / 100) . $strGlue . $arr[$i];
    }
}
